<template>
  <div>
    <el-button type="primary" @click="startAnimation">开始</el-button>
    <el-button type="warning" @click="pauseAnimation">暂停</el-button>
    <el-button type="info" @click="resetAnimation">重置</el-button>
    <div id="map-container"></div>
  </div>
</template>
<script>
import { Map, View } from 'ol'
import { Tile as TileLayer } from 'ol/layer'
import {fromLonLat, get} from 'ol/proj';
import { getWidth, getTopLeft } from 'ol/extent'
import { WMTS } from 'ol/source'
import WMTSTileGrid from 'ol/tilegrid/WMTS'
import { defaults as defaultControls} from 'ol/control';
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Feature from "ol/Feature";
import {LineString, Point} from "ol/geom";
import {Icon, Stroke, Style} from "ol/style";

export const projection = get("EPSG:4326");
const projectionExtent = projection.getExtent();
const size = getWidth(projectionExtent) / 256;
const resolutions = [];
for (let z = 0; z < 19; ++z) {
  resolutions[z] = size / Math.pow(2, z);
}

export default {
  data() {
    return {
      map:null,
      //点位信息
      pointList: [
        [120.430070,31.938140],
        [120.428570,31.939100],
        [120.429530,31.941680],
        [120.431240,31.943580],
        [120.432410,31.944820],
        [120.433600,31.943970],
      ],
      //用于存放车辆、起始点位和折线的图层
      vectorLayer: new VectorLayer({
        source: new VectorSource(),
        zIndex: 2,
      }),
      //车辆
      carFeature:null,
      //动画开始标记
      isAnimating: false,
      //动画开始时间/动画暂停时间
      animationStartTime:0,
      //索引
      currentIndex:0,
      // 每个点之间的移动时间（毫秒）
      speed: 1000,
      //记录上一个动画的运行时间
      lastAnimationTime: 0,
    }
  },
  mounted(){
    this.initMap() // 加载矢量底图
  },
  methods:{
    initMap() {
      const KEY = '你申请的KEY'

      this.map = new Map({
        target: 'map-container',
        layers: [
          // 底图
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/vec_c/wmts?tk=${KEY}`,
              layer: 'vec', // 矢量底图
              matrixSet: 'c', // c: 经纬度投影 w: 球面墨卡托投影
              style: "default",
              crossOrigin: 'anonymous', // 解决跨域问题 如无该需求可不添加
              format: "tiles", //请求的图层格式，这里指定为瓦片格式
              wrapX: true, // 允许地图在 X 方向重复（环绕）
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          }),
          // 标注
          new TileLayer({
            source: new WMTS({
              url: `http://t{0-6}.tianditu.com/cva_c/wmts?tk=${KEY}`,
              layer: 'cva', //矢量注记
              matrixSet: 'c',
              style: "default",
              crossOrigin: 'anonymous',
              format: "tiles",
              wrapX: true,
              tileGrid: new WMTSTileGrid({
                origin: getTopLeft(projectionExtent),
                resolutions: resolutions,
                matrixIds: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15','16','17','18']
              })
            })
          })
        ],
        view: new View({
          center: [120.430070,31.938140],
          projection: projection,
          zoom: 16,
          maxZoom: 17,
          minZoom: 1
        }),
        //加载控件到地图容器中
        controls: defaultControls({
          zoom: false,
          rotate: false,
          attribution: false
        })
      });
      // 将矢量层添加到地图
      this.map.addLayer(this.vectorLayer);
      this.createStartPoint();
      this.createEndPoint();
      this.createCar();
      this.drawLine();
    },
    /**
     * 创建开始点位
     */
    createStartPoint(){
      // 创建feature要素，一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[0]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/start.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10,
          }),

      );
      this.vectorLayer.getSource().addFeature(feature);
    },

    //创建结束点位
    createEndPoint(){
      // 创建feature要素，一个feature就是一个点坐标信息
      let feature = new Feature({
        geometry: new Point(this.pointList[this.pointList.length-1]),
      });
      // 设置要素的图标
      feature.setStyle(
          new Style({
            // 设置图片效果
            image: new Icon({
              src: 'http://lbs.tianditu.gov.cn/images/bus/end.png',
              // anchor: [0.5, 0.5],
              scale: 1,
            }),
            zIndex: 10
          }),

      );
      this.vectorLayer.getSource().addFeature(feature);
    },

    createCar(){
      // 创建feature要素，一个feature就是一个点坐标信息
      this.carFeature = new Feature({
        geometry: new Point(this.pointList[0]),
      });
      const currentPoint = fromLonLat(this.pointList[0]);
      const nextPoint = fromLonLat(this.pointList[1]);
      let rotation = this.calculateRotation(currentPoint,nextPoint);
      this.carFeature.setStyle(this.getVehicleStyle(rotation));
      this.vectorLayer.getSource().addFeature(this.carFeature);
    },

    //计算旋转角度
    calculateRotation(currentPoint,nextPoint){
      const dx = nextPoint[0] - currentPoint[0];
      const dy = nextPoint[1] - currentPoint[1];
      return Math.atan2(dy,dx);
    },
    //获取车辆的样式
    getVehicleStyle(rotation) {
      return new Style({
        // 设置图片效果
        image: new Icon({
          src: 'http://lbs.tianditu.gov.cn/images/openlibrary/car.png',
          // anchor: [0.5, 0.5],
          scale: 1,
          rotation: -rotation,
        }),
        zIndex: 5,
      })
    },

    drawLine(){
      // 创建线特征
      const lineFeature = new Feature({
        geometry: new LineString(this.pointList),
      });

      // 设置线样式
      const lineStyle = new Style({
        stroke: new Stroke({
          color: '#25C2F2',
          width: 4,
          lineDash: [10, 8], // 使用点划线 数组的值来控制虚线的长度和间距
        }),

      });
      lineFeature.setStyle(lineStyle);

      // 创建矢量层并添加特征
      const vectorSource = new VectorSource({
        features: [lineFeature],
      });
      const vectorLayer = new VectorLayer({
        source: vectorSource,
        zIndex: 1
      });

      // 将矢量层添加到地图
      this.map.addLayer(vectorLayer);
      // 设置地图视图以适应路径
      this.map.getView().fit(lineFeature.getGeometry().getExtent(), {
        padding: [20, 20, 20, 20],
        maxZoom: 18,
      });
    },

    startAnimation() {
      // 如果没有开始动画，则开始动画
      if (!this.isAnimating) {
        this.isAnimating = true;
        //这里存放的是暂停动画的时间，下面启动动画后，会将当前时间减去暂停动画的时间就是动画已运行的时间，这样就不会从头开始了
        //当前时间比如为900ms，用900ms减去500ms，可以计算出当前暂停了400ms
        this.animationStartTime = performance.now() - (this.lastAnimationTime || 0);
        // 继续或者启动动画
        // 计算经过时间：elapsed = timestamp - this.animationStartTime; 900ms减去400ms 可以算出已经运行了500ms 也就是上次动画所运行的时间了
        this.animateVehicle();
      }
    },

    // 暂停动画
    pauseAnimation() {
      if (this.isAnimating) {
        this.isAnimating = false;
        // 保存当前动画运行的时间 比如已经运行了500ms
        this.lastAnimationTime = performance.now() - this.animationStartTime;
      }
    },
    // 重置动画
    resetAnimation() {
      // 停止动画
      this.isAnimating = false;
      // 重置索引
      this.currentIndex = 0;
      // 将车辆位置重置到起始点
      this.carFeature.getGeometry().setCoordinates(this.pointList[0]);
      const currentPoint = fromLonLat(this.pointList[0]);
      const nextPoint = fromLonLat(this.pointList[1]);
      let rotation = this.calculateRotation(currentPoint,nextPoint);
      // 重置车辆样式
      this.carFeature.setStyle(this.getVehicleStyle(rotation));
    },

    //车辆行驶动画
    animateVehicle(timestamp) {
      if (!this.isAnimating || this.currentIndex >= this.pointList.length - 1) return;

      const currentPoint = this.pointList[this.currentIndex];
      const nextPoint = this.pointList[this.currentIndex + 1];

      // 计算经过的时间
      const elapsed = timestamp - this.animationStartTime;
      const progress = Math.min(elapsed / this.speed, 1);

      // 计算当前位置的坐标
      const coordinates = [
        currentPoint[0] + (nextPoint[0] - currentPoint[0]) * progress,
        currentPoint[1] + (nextPoint[1] - currentPoint[1]) * progress,
      ];

      // 更新车辆位置
      this.carFeature.getGeometry().setCoordinates(coordinates);

      if (progress === 1) {
        this.currentIndex++;
        this.animationStartTime = timestamp; // 重置动画开始时间
        this.lastAnimationTime = 0; // 移动到下一个点时重置
      }

      // 计算下一个点的角度
      const angle = this.calculateRotation(currentPoint, nextPoint);
      this.carFeature.setStyle(this.getVehicleStyle(angle)); // 更新样式以反映新的朝向

      // 继续动画
      if (this.currentIndex < this.pointList.length - 1) {
        requestAnimationFrame(this.animateVehicle);
      } else {
        this.isAnimating = false; // 动画结束
      }
    },
  },
}
</script>
<style scoped>
#map-container {
  width: 100%;
  height: 100vh;
}
</style>
